
#include "FileLoader.h"
#include "stdlib.h"
#include <stdio.h>
#include <stddef.h>
#include <Integer.h>
#include <Float.h>
#include <GlobalVar.h>


void initFileLoader(FileLoader* self, FileReader* r) {
	self->reader = r;
    self->stingTable = (List*)malloc(sizeof(List));
    list_init(self->stingTable);
}

FileLoader* fileloader_allocate(const char* filename){
    FileReader* temp = (FileReader*)malloc(sizeof(FileReader));
    initFileReader(temp,filename);
    FileLoader* fl = (FileLoader*)malloc(sizeof(FileLoader));
    initFileLoader(fl,temp);
    return fl;
}
void fileloader_destroy(FileLoader* self) {
    list_destroy(self->stingTable);
    destroyFileReader(self->reader);
    free(self);
}

static String* getString(FileReader* read) {
    int length = readInt(read);
    char* chs=(char*)malloc(sizeof(char)*length);
    int i = 0;
    while (i < length) {
        chs[i++] = readChar(read);
    }
    String* temp = string_allocate_const(chs,length);
    free(chs);
    return temp;
}

static String* getByteCode(FileReader* read) {
    char flag = readChar(read);
    if (flag == 's') {
        return getString(read);
    }
}

static Code* fileParse(FileLoader*);

static List* getList(FileLoader* self) {
    int length = readInt(self->reader);
    List* consts = list_allocate_const();
    for (int i = 0; i < length; i++) {
        char type = readChar(self->reader);
        switch (type) {
            case 'c':
                list_append(consts, (Object *) (fileParse(self)));
                break;
            case 'i':{
                Integer * it = (Integer*)malloc(sizeof(Integer));
                int_init(it, readInt(self->reader));
                list_append(consts, (Object *) it);
                break;
            }
            case 'g': {
                Float *f = (Float *) malloc(sizeof(Float));
                float_init(f, readDouble(self->reader));
                list_append(consts, (Object *) f);
            }
                break;
            case 't': {
                Object* s = (Object*)getString(self->reader);
                list_append(consts, s);
                list_append(self->stingTable, s);
            }
                break;
            case 's':
                list_append(consts, (Object *) getString(self->reader));
                break;
            case 'R':
                list_append(consts, list_get(self->stingTable, readInt(self->reader)));
                break;
            case '(':
                list_append(consts, (Object *) getList(self));
                break;
            case 'N':
                list_append(consts, &None);
                break;
            default:
               printf("parse error type: %c", type);
        }
    }
    return consts;
}


static List* getTable(FileLoader* self) {
    if (readChar(self->reader) == '(') return getList(self);
    else {
        unRead(self->reader);
        return NULL;
    }
}




static String* getName(FileLoader* self) {
    char c = readChar(self->reader);
    if (c == 's') return getString(self->reader);
    else if (c == 't') {
        String* s = getString(self->reader);
        list_append(self->stingTable, (Object *) s);
        return s;
    }
    else if (c == 'R') {
        return (String*) list_get(self->stingTable, readInt(self->reader));
    }
    else return NULL;
}

static Code* fileParse(FileLoader* self) {
    Code* code =(Code*)malloc(sizeof(Code));
    int arg = readInt(self->reader);
    int nlocals = readInt(self->reader);
    int stackSize = readInt(self->reader);
    int flag = readInt(self->reader);
    String* byteCode = getByteCode(self->reader);
    List* consts= getTable(self);
    List* names = getTable(self);
    List* varNames = getTable(self);
    List* freeVars = getTable(self);
    List* cell_vars = getTable(self);
    String* fileName = getName(self);
    String* moduleName = getName(self);
    int lineNumber = readInt(self->reader);
    String* lnotab = getName(self);
    initCode(code, arg, nlocals, stackSize, flag, byteCode, consts, names, varNames, freeVars, cell_vars, fileName, moduleName, lineNumber,lnotab);
    //printMessage("code load success!\n");
    return code;
}


Code* parse(FileLoader* self) {
	int magic = readInt(self->reader);
	int time = readInt(self->reader);
	char  typeChar = readChar(self->reader);
	if (typeChar == 'c') {
		return fileParse(self);
	}
	else printf("what is this?");
}







